import ast
import logging
from collections import defaultdict
from typing import Dict, List, Set, Optional, Any, Type

from 程序核心代码.ast节点.节点分析.分析器基类 import 分析器基类
from 程序核心代码.ast节点.节点定义.基础定义.ast节点基础定义 import ast节点基础模型

logger = logging.getLogger(__name__)

class 类型分析器(分析器基类):
    """类型分析器类，用于分析节点的类型信息和类型关系"""
    
    def __init__(self):
        super().__init__()
        self.类型映射: Dict[ast节点基础模型, Type] = {}
        self.类型约束: Dict[ast节点基础模型, Set[Type]] = defaultdict(set)
        self.类型冲突: List[Dict[str, Any]] = []
        self.类型推导缓存: Dict[ast节点基础模型, Type] = {}
        
    def 分析节点(self, 节点: ast节点基础模型) -> Dict[str, Any]:
        """分析指定节点的类型信息"""
        try:
            if not self.验证节点(节点):
                return {}
                
            # 分析节点类型
            节点类型 = self._推导节点类型(节点)
            if 节点类型:
                self.类型映射[节点] = 节点类型
                
            # 分析类型约束
            self._分析类型约束(节点)
            
            # 验证类型一致性
            self._验证类型一致性(节点)
            
            # 记录分析结果
            self.分析结果[节点._节点ID] = {
                "推导类型": 节点类型.__name__ if 节点类型 else None,
                "类型约束": [约束.__name__ for 约束 in self.类型约束[节点]],
                "类型冲突": self._获取节点类型冲突(节点)
            }
            
            self.标记已分析(节点)
            return self.分析结果[节点._节点ID]
            
        except Exception as e:
            self.记录分析日志(f"类型分析失败: {str(e)}", "error")
            return {}
            
    def _推导节点类型(self, 节点: ast节点基础模型) -> Optional[Type]:
        """推导节点的类型"""
        # 检查缓存
        if 节点 in self.类型推导缓存:
            return self.类型推导缓存[节点]
            
        推导类型 = None
        
        # 根据AST节点类型推导
        if hasattr(节点, '_ast节点'):
            推导类型 = self._从AST推导类型(节点._ast节点)
            
        # 根据接口连接推导
        if not 推导类型:
            推导类型 = self._从接口推导类型(节点)
            
        # 缓存结果
        if 推导类型:
            self.类型推导缓存[节点] = 推导类型
            
        return 推导类型
        
    def _从AST推导类型(self, ast节点: ast.AST) -> Optional[Type]:
        """从AST节点推导类型"""
        if isinstance(ast节点, ast.Num):
            return int if isinstance(ast节点.n, int) else float
        elif isinstance(ast节点, ast.Str):
            return str
        elif isinstance(ast节点, ast.List):
            return list
        elif isinstance(ast节点, ast.Dict):
            return dict
        elif isinstance(ast节点, ast.Name):
            # TODO: 从作用域查找变量类型
            return None
        elif isinstance(ast节点, ast.Call):
            # TODO: 从函数返回类型推导
            return None
        return None
        
    def _从接口推导类型(self, 节点: ast节点基础模型) -> Optional[Type]:
        """从节点接口连接推导类型"""
        for 接口 in 节点.节点接口.values():
            if 接口.类型 == "数据流" and 接口.连接列表:
                for 连接接口 in 接口.连接列表:
                    连接节点 = 连接接口.节点模型
                    if 连接节点 in self.类型映射:
                        return self.类型映射[连接节点]
        return None
        
    def _分析类型约束(self, 节点: ast节点基础模型) -> None:
        """分析节点的类型约束"""
        if not hasattr(节点, '_ast节点'):
            return
            
        class 类型约束访问器(ast.NodeVisitor):
            def __init__(self, 外部实例):
                self.外部实例 = 外部实例
                
            def visit_Compare(self, ast节点):
                # 比较操作的操作数类型应该兼容
                左操作数类型 = self.外部实例._从AST推导类型(ast节点.left)
                if 左操作数类型:
                    self.外部实例.类型约束[节点].add(左操作数类型)
                    
                for 比较器 in ast节点.comparators:
                    比较器类型 = self.外部实例._从AST推导类型(比较器)
                    if 比较器类型:
                        self.外部实例.类型约束[节点].add(比较器类型)
                        
            def visit_BinOp(self, ast节点):
                # 二元操作的操作数类型应该兼容
                左类型 = self.外部实例._从AST推导类型(ast节点.left)
                右类型 = self.外部实例._从AST推导类型(ast节点.right)
                
                if 左类型:
                    self.外部实例.类型约束[节点].add(左类型)
                if 右类型:
                    self.外部实例.类型约束[节点].add(右类型)
                    
        访问器 = 类型约束访问器(self)
        访问器.visit(节点._ast节点)
        
    def _验证类型一致性(self, 节点: ast节点基础模型) -> None:
        """验证节点的类型一致性"""
        if 节点 not in self.类型映射:
            return
            
        当前类型 = self.类型映射[节点]
        
        # 检查与类型约束的一致性
        for 约束类型 in self.类型约束[节点]:
            if not self._类型兼容(当前类型, 约束类型):
                self.类型冲突.append({
                    "节点模型": 节点._节点ID,
                    "当前类型": 当前类型.__name__,
                    "约束类型": 约束类型.__name__,
                    "冲突描述": "类型不满足约束"
                })
                
        # 检查与连接节点的类型一致性
        for 接口 in 节点.节点接口.values():
            if 接口.类型 == "数据流":
                for 连接接口 in 接口.连接列表:
                    连接节点 = 连接接口.节点模型
                    if 连接节点 in self.类型映射:
                        连接类型 = self.类型映射[连接节点]
                        if not self._类型兼容(当前类型, 连接类型):
                            self.类型冲突.append({
                                "节点模型": 节点._节点ID,
                                "当前类型": 当前类型.__name__,
                                "连接类型": 连接类型.__name__,
                                "冲突描述": "连接节点类型不兼容"
                            })
                            
    def _类型兼容(self, 类型1: Type, 类型2: Type) -> bool:
        """检查两个类型是否兼容"""
        # TODO: 实现更复杂的类型兼容性检查
        return 类型1 == 类型2 or issubclass(类型1, 类型2) or issubclass(类型2, 类型1)
        
    def _获取节点类型冲突(self, 节点: ast节点基础模型) -> List[Dict[str, str]]:
        """获取节点相关的类型冲突"""
        return [冲突 for 冲突 in self.类型冲突 if 冲突["节点模型"] == 节点._节点ID]
        
    def 获取类型报告(self) -> Dict[str, Any]:
        """获取完整的类型分析报告"""
        return {
            "类型映射": {节点._节点ID: 类型.__name__ for 节点, 类型 in self.类型映射.items()},
            "类型约束": {节点._节点ID: [约束.__name__ for 约束 in 约束集]
                      for 节点, 约束集 in self.类型约束.items()},
            "类型冲突": self.类型冲突
        }
        
    def 重置(self) -> None:
        """重置分析器状态"""
        super().重置()
        self.类型映射.clear()
        self.类型约束.clear()
        self.类型冲突.clear()
        self.类型推导缓存.clear()
        
    def __str__(self) -> str:
        """返回类型分析器的字符串表示"""
        return f"类型分析器(节点数={len(self.类型映射)}, 冲突数={len(self.类型冲突)})" 